/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alemosbarbosa.com/

 Copyright (c) 2010 Alexandre Lemos Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#include "cnome_config.h"

#include "iterator.h"

namespace cnome {
using namespace boost::wave;

const iterator iterator::end;

iterator* iterator::m_farest = new iterator(); //&stt_lcl_farest;

iterator::iterator(base_type const& p) 
    : iterator::iterator_adaptor_(p), m_pos(0) {
    if (    *this != end 
         && (    (**this == T_PP_LINE) || (**this == T_SPACE) || (**this == T_SPACE2) || (**this == T_NEWLINE) 
              || (**this == T_CPPCOMMENT) || (**this == T_PP_PRAGMA) || (**this == T_MSEXT_CDECL)
              || (**this == T_EOF) ||  (**this == T_MSEXT_ASM) // TODO: Implement a negation operator in order to implement a new mechanism to handle a MS asm block
			                                                   // alb 07jun2011
			  ||  (**this == T_CCOMMENT)  // EOF is sent for MACRO= (empty)
              || (**this == T_DIVIDE && (*this)->get_value() == "//") 
            ) 
       )
        ++(*this);
}

void iterator::increment() {
    const char* pc = (*this != end)?(*this)->get_value().c_str():0;
    // First verify if the current position is ok
    if ((*this != end) && (    (**this == T_PP_LINE) || (**this == T_CPPCOMMENT) || (**this == T_PP_PRAGMA) 
                            || ((**this == T_DIVIDE) && ((*this)->get_value() == "//") )   // Handle the weird case of
                          )                                                                // #    define    _WPAD    /##/
                                                                                         // _WPAD a;
       ) {
        while ((*this != end) && (**this != T_NEWLINE)) {  // Skip everthing until end of line
            ++base_reference();
            pc = (*this != end)?(*this)->get_value().c_str():0;
        }
    }
    
    ++base_reference();
    pc = (*this != end)?(*this)->get_value().c_str():0;

    while (    (*this != end) 
            && (    (**this == T_PP_LINE) || (**this == T_SPACE) || (**this == T_SPACE2) || (**this == T_NEWLINE) 
                 || (**this == T_CPPCOMMENT) || (**this == T_PP_PRAGMA) || (**this == T_MSEXT_CDECL)
                 || (**this == T_EOF) || (**this == T_CCOMMENT) 
                 || (**this == T_DIVIDE && (*this)->get_value() == "//" )
               ) 
          ) {
        if (    (**this == T_PP_LINE) || (**this == T_CPPCOMMENT) || (**this == T_PP_PRAGMA) 
            || ((**this == T_DIVIDE) && ((*this)->get_value() == "//") )) {
            while ((*this != end) && (**this != T_NEWLINE)) {  // Skip everthing until end of line
                ++base_reference();
                pc = (*this != end)?(*this)->get_value().c_str():0;
            }
        }
        while ((*this != end) && (    (**this == T_SPACE) || (**this == T_SPACE2) || (**this == T_NEWLINE) //|| (**this == T_CPPCOMMENT) 
                                   //|| (**this == T_MSEXT_CDECL) 
                                   || (**this == T_EOF) || (**this == T_CCOMMENT))) {
            ++base_reference();
            pc = (*this != end)?(*this)->get_value().c_str():0;
        }
    }

    //// Handle weird case of
    //// #    define    _WPAD    /##/
    //// _WPAD a;
    //while (    (*this != end)
    //        && (**this == T_DIVIDE && (*this)->get_value() == "//" ) ) {
    //    while (*this != end && **this != T_NEWLINE) {
    //        ++base_reference();
    //        pc = (*this != end)?(*this)->get_value().c_str():0;
    //    }
    //    while (*this != end && **this == T_NEWLINE) {
    //        ++base_reference();
    //        pc = (*this != end)?(*this)->get_value().c_str():0;
    //    }
    //}

    // TODO: Implement a negation operator in order to implement a new mechanism to handle a MS asm block
	// alb 07jun2011   
	while (*this != end && **this == T_MSEXT_ASM) {
        handleMSASM();
        pc = (*this != end)?(*this)->get_value().c_str():0;
    }

#if defined(CNOME_DEBUG_)
    if (**this == T_IDENTIFIER) {  // Search symbol table
        std::string curScope;
        get_scope(curScope, (*this)->get_value().c_str());
        scopesFromStr scopes(curScope);
        while (scopes.nextScope().size()) {
            if (symbol* it = find(cnome_symbols, scopes.current_scope().c_str())) {
                (*this)->set_token_id(*it);
                break;
            }    
        }
    }
#endif

    m_pos++;
    if (m_pos > m_farest->m_pos) {
        *m_farest = *this;
    }
}
//
//const iterator iterator::operator++(int) {
//    token_t tk = **this;
//
//    iterator clone = *this;
//    operator++();
//
//#if defined(CNOME_DEBUG_)
//	if (*clone == T_IDENTIFIER) {  // Search symbol table
//        std::string curScope;
//        get_scope(curScope, clone->get_value().c_str());
//        scopesFromStr scopes(curScope);
//        while (scopes.nextScope().size()) {
//            if (symbol* it = find(cnome_symbols, scopes.current_scope().c_str())) {
//                clone->set_token_id(*it);
//                break;
//            }    
//        }
//    }
//#endif
//
//    return clone;
//}

token_t& iterator::dereference() const {
    using namespace boost::wave;

    token_t tk = *base_reference();
#ifdef _DEBUG
    const char* val = tk.get_value().c_str();
#endif
    if (   *base_reference() == T_CLASS 
        && base_reference()->get_value() != "class") // Handle the weird case of preprocessor "class##n"
        base_reference()->set_token_id(T_IDENTIFIER);

    return *base_reference();
}

void iterator::handleMSASM() {
    token_t aux = *base_reference();
    if (!(*this != end && **this == T_MSEXT_ASM))    
        return; // Nothing to do

    // Get next meaningfull token
    do {
       ++base_reference();
       aux = *base_reference();
    }
    while (*this != end && (**this == T_CCOMMENT || **this == T_CPPCOMMENT || **this == T_NEWLINE || **this == T_SPACE)); // TODO: Verify valid tokens here
    token_id endTk;
    for (endTk = (**this==T_LEFTBRACE)?T_RIGHTBRACE:T_NEWLINE; *this != end && **this != endTk && **this != T_RIGHTBRACE; // Skip end token
             ++base_reference())
         aux = *base_reference();
    if (*this != end && **this == endTk) {
       ++base_reference();
       aux = *base_reference();
    }
    while (    (*this != end) 
            && (    (**this == T_PP_LINE) || (**this == T_SPACE) || (**this == T_NEWLINE) 
                 || (**this == T_CPPCOMMENT) || (**this == T_PP_PRAGMA) || (**this == T_MSEXT_CDECL)
                 || (**this == T_EOF) || (**this == T_CCOMMENT)
               ) 
          ) {
        if (*this != end &&  (**this == T_PP_LINE || **this == T_CPPCOMMENT || **this == T_PP_PRAGMA))
            while (*this != end && **this != T_NEWLINE)
                ++base_reference();
        while ((*this != end) && (    (**this == T_SPACE) || (**this == T_NEWLINE) || (**this == T_CPPCOMMENT) 
                                   || (**this == T_MSEXT_CDECL) || (**this == T_EOF) || (**this == T_CCOMMENT)))
            ++base_reference();
    }
}

bool operator<(const iterator& a, const iterator& b) {
    return a.m_pos < b.m_pos;
}

bool operator==(const iterator& a, const iterator& b) {
    bool a_isEof = a.base() == iterator::end.base();
    bool b_isEof = b.base() == iterator::end.base();

    if (a_isEof && b_isEof)
        return true;  // Both are eof
    if (a_isEof ^ b_isEof)
        return false; // Only one is eof

    return a.m_pos == b.m_pos;
}
}  //  namespace cnome
